package org.lestr.secuel.sogl.objets3D;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

import java.util.Map;
import org.lestr.secuel.m3ds.IUsine;
import org.lestr.secuel.m3ds.maths.IPoint3d;
import org.lestr.secuel.m3ds.maths.IPoint2d;
import org.lestr.secuel.m3ds.objets3D.Materiau;
import org.lestr.secuel.m3ds.objets3D.IObjet3d;
import org.lestr.secuel.m3ds.objets3D.IApparence;
import org.lestr.secuel.m3ds.objets3D.EcouteurTexture;
import org.lestr.secuel.m3ds.objets3D.IDimensionTexture;
import org.lestr.secuel.m3ds.objets3D.IPositionTexture;
import org.lestr.secuel.m3ds.objets3D.ITriangle;

public class Texture implements IApparence {


    // Déclaration des attributs
    private IObjet3d objetParent;


    private Materiau matériauStandard;


    private Map<ITriangle, Materiau> matériaux;


    private IPositionTexture position;


    private IDimensionTexture dimension;

    private Collection<EcouteurTexture> écouteurs;


    private Collection<IPoint2d> coordonnées;


    private Collection<IPoint3d> normales;


    private boolean autoTexturage;


    private boolean autoNormage;


    /** Constructeur */
    public Texture(IUsine usine, 
                   IObjet3d objetParent) {

        // Instanciation des attributs
        this.objetParent = objetParent;
        matériauStandard = new SOGLMateriau();
        matériaux = new HashMap<ITriangle, Materiau>();
        position = usine.positionTexture(this);
        dimension = usine.dimensionTexture(this);
        écouteurs = new ArrayList<EcouteurTexture>();
        coordonnées = null;
        autoTexturage = true;
        autoNormage = true;

    }// FIN Constructeur


    /** Ajoute un écouteur */
    @Override
    public void ajoutEcouteur(EcouteurTexture écouteur) {

        écouteurs.add(écouteur);

    }// FIN ajoutEcouteur


    /** Retire un écouteur */
    @Override
    public void retraitEcouteur(EcouteurTexture écouteur) {

        écouteurs.remove(écouteur);

    }// FIN retraitEcouteur


    /** Retourne l'objet 3D associé à la texture */
    @Override
    public IObjet3d obtenirObjet3d() {

        return objetParent;

    }// FIN obtenirObjet3d


    /** Retourne le matériau par défaut de la texture */
    @Override
    public Materiau obtenirMatériauStandard() {

        return matériauStandard;

    }// FIN retMatériauStandard


    /** Défini le matériau d'un triangle. Null pour utiliser le matériau par défaut */
    @Override
    public void définirMatériau(Materiau matériau,
                            ITriangle triangle) {

        // Si le matériaux change vraiement
        if (obtenirMatériau(triangle) != matériau) {

            // Mémorise
            Materiau ancienMatériau = obtenirMatériau(triangle);
            matériaux.put(triangle, matériau);

            // Prévient les écouteurs
            for (EcouteurTexture écouteur : écouteurs)
                écouteur.matériauChangé(this, triangle, ancienMatériau);

        }

    }// FIN defMatériau


    /** Retourne le matériau d'un triangle. Null pour utiliser le matériau par défaut */
    @Override
    public Materiau obtenirMatériau(ITriangle triangle) {

        return matériaux.get(triangle);

    }// FIN retMatériau


    /** Défini si les coordonnées de texture doivent être automatiquement calculées ou non */
    @Override
    public void définirTexturageAutomatique(boolean auto) {

        // Si l'auto-textutage change vraiment
        if (auto != autoTexturage) {

            // Mémorise
            autoTexturage = auto;

            // Prévient les écouteurs
            for (EcouteurTexture écouteur : écouteurs)
                écouteur.autoTexturageChangé(this);

        }

    }// FIN defAutoTexturage


    /** Retourne vrai si les coordonnées de texture sont automatiquement caculée */
    @Override
    public boolean estTexturageAutomatique() {

        return autoTexturage;

    }// FIN retEstAutoTexturé


    /** Défini les coordonnées de texture. Il doit y avoir autant de points que de sommets de triangles dans l'objet et conserver le même ordre */
    @Override
    public void setCoordonnées(Collection<IPoint2d> coordonnées) {

        // Si différent des anciennes
        if (coordonnées != this.coordonnées) {

            // Mémorise
            Collection<IPoint2d> anciennesCoordonnées = this.coordonnées;
            this.coordonnées = coordonnées;

            // Prévient les écouteurs
            for (EcouteurTexture écouteur : écouteurs)
                écouteur.coordonnéesChangées(this, anciennesCoordonnées);

        }

    }// FIN defCoordonnées


    /** Retourne les coordonnées de texture */
    @Override
    public Collection<IPoint2d> obtenirCoordonnées() {

        return coordonnées;

    }// FIN retCoordonnées


    /** Défini si les normales des sommets des triangles sont auto-calculées */
    @Override
    public void définirNormalesAutomatiques(boolean auto) {

        // Si ça change vraiement
        if (autoNormage != auto) {

            // Mémorise
            autoNormage = auto;

            // Prévient les écouteurs
            for (EcouteurTexture écouteur : écouteurs)
                écouteur.autoNormalesChangé(this);

        }

    }// FIN defAutoNormales


    /** Retourne vrai si les normales des sommets des triangles sont auto-calculées */
    @Override
    public boolean sontNormalesAutomatiques() {

        return autoNormage;

    }// FIN retEstAutoNormales


    /** Défini les normales. Il doit y avoir autant de points que de sommets de triangles dans l'objet et conserver le même ordre */
    @Override
    public void définirNormales(Collection<IPoint3d> normales) {

        // Si les normales changent vraiement
        if (this.normales != normales) {

            // Mémorise
            Collection<IPoint3d> anciennesNormales = this.normales;
            this.normales = normales;

            // Prévient les écouteurs
            for (EcouteurTexture écouteur : écouteurs)
                écouteur.normalesChangées(this, anciennesNormales);

        }

    }// FIN defNormales


    /** Retourne les normales. Il doit y avoir autant de points que de sommets de triangles dans l'objet et conserver le même ordre */
    @Override
    public Collection<IPoint3d> obtenirNormales() {

        return normales;

    }// FIN obtenirNormales


    /** Retourne la positionObjet3d X de la texture */
    @Override
    public IPositionTexture getPosition() {

        return position;

    }// FIN getPosition


    /** Retourne la dimensionObjet3d X de la texture */
    @Override
    public IDimensionTexture getDimension() {

        return dimension;

    }// FIN getDimension


}// FIN Classe
